package com.intco.ait.quotation.api.common.utils;

import org.springframework.stereotype.Service;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.concurrent.ThreadLocalRandom;

@Service
public class UIDGenerator {
    // 起始时间戳 (2024-01-01)
    private static final long EPOCH = 1746028800000L;
    
    // 各部分位数
    private static final long DATA_CENTER_ID_BITS = 5L;
    private static final long WORKER_ID_BITS = 5L;
    private static final long SEQUENCE_BITS = 12L;

    // 最大值计算
    private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
    private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);

    // 位偏移
    private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
    private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;

    // 节点参数
    private final long dataCenterId;
    private final long workerId;
    
    // 并发控制
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    /**
     * 自动根据本机MAC和PID生成WorkerId
     */
    public UIDGenerator() {
        this.dataCenterId = getDataCenterId();
        this.workerId = getWorkerId(dataCenterId);
    }

    /**
     * 自定义节点ID构造
     */
    public UIDGenerator(long dataCenterId, long workerId) {
        if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
            throw new IllegalArgumentException("DataCenterId超出范围");
        }
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException("WorkerId超出范围");
        }
        this.dataCenterId = dataCenterId;
        this.workerId = workerId;
    }

    /**
     * 生成下一个ID (线程安全)
     */
    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            // 时钟回拨处理: 启动时回拨直接抛出异常, 运行中回拨做短暂等待
            if (lastTimestamp - timestamp < 5000) {
                try {
                    wait(lastTimestamp - timestamp << 1);
                    timestamp = timeGen();
                } catch (InterruptedException e) {
                    throw new RuntimeException("时钟回拨异常", e);
                }
            } else {
                throw new RuntimeException("时钟回拨超过5秒, 拒绝生成ID");
            }
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & SEQUENCE_MASK;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            // 不同毫秒内序列号随机初始化，防止低并发时ID连续
            sequence = ThreadLocalRandom.current().nextLong(0, 2);
        }

        lastTimestamp = timestamp;

        return ((timestamp - EPOCH) << TIMESTAMP_SHIFT)
                | (dataCenterId << DATA_CENTER_ID_SHIFT)
                | (workerId << WORKER_ID_SHIFT)
                | sequence;
    }

    /**
     * 等待下一毫秒
     */
    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    /**
     * 当前毫秒数
     */
    private long timeGen() {
        return System.currentTimeMillis();
    }

    /**
     * 自动生成数据中心ID (基于MAC地址)
     */
    private static long getDataCenterId() {
        try {
            InetAddress ip = InetAddress.getLocalHost();
            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
            byte[] mac = network.getHardwareAddress();
            return ((mac[4] & 0xFF) | (mac[5] & 0xFF) << 8) & MAX_DATA_CENTER_ID;
        } catch (Exception e) {
            return ThreadLocalRandom.current().nextLong(0, MAX_DATA_CENTER_ID + 1);
        }
    }

    /**
     * 自动生成WorkerId (基于PID)
     */
    private static long getWorkerId(long dataCenterId) {
        String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
        return (dataCenterId + pid.hashCode()) & MAX_WORKER_ID;
    }

    // 使用示例
    public static void main(String[] args) {
        UIDGenerator generator = new UIDGenerator();
        for (int i = 0; i < 10; i++) {
            System.out.println("生成的UID: " + generator.nextId());
        }
    }
}